iT邦幫忙

2021 iThome 鐵人賽

DAY 16
0

終於度過前面枯燥乏味的內容了...(但它們都很重要,也與今天的主題有關)
今天要來進入重點項目
我們想要進一步多了解Mysql,無不就是希望當語法跑太慢的時候,我們可以知道怎麼優化它!!

為了故事順利發展,先把之前的例子再貼一次

mysql> create table single_table(
    -> id int not null auto_increment,
    -> key1 varchar(10),
    -> key2 int,
    -> key3 varchar(100),
    -> key_part1 varchar(100),
    -> key_part2 varchar(100),
    -> key_part3 varchar(100),
    -> common_field varchar(100),
    -> primary key (id),
    -> key idx_key1 (key1),
    -> unique key uk_key2 (key2),
    -> key idx_key3 (key3),
    -> key idx_key_part(key_part1, key_part2, key_part3)
    -> ) engine=InnoDB charset=utf8;
Query OK, 0 rows affected, 1 warning (0.05 sec)

為id列建立的聚簇索引
為key1列建立的idx_key1二級索引
為key2列建立的uk_key2二級索引,且是唯一
為key3列建立的idx_key3二級索引
為key_part1、key_part2、key_part3列建立的idx_key_part二級索引,這也是個聯合索引

優化查詢語法是一個很大的範圍,學會跑之前要先知道怎麼走!

所以我們要先知道
存取方法的概念
我們都有用過google map,在地圖上設立了起點與終點後,就要決定使用何種交通工具來到達目的地。
而Mysql查詢語法的過程跟這個也有點像,不管你過程使用什麼存取方法(交通工具),只要能拿到需要的資料(到達目的地)就好。

來看看有那些存取方法
const
透過主鍵或唯一二級索引與常數的相等比較來搜尋一筆紀錄,這個存取方法就是const(意思是常數等級的,代價可忽略不計),這樣的方法速度非常快。
看個例子:

select * from single_table where id = 1438;

透過主鍵與常數的比較,mysql會直接利用主鍵值在聚簇索引內定位對應的使用者紀錄。

select * from single_table where key2 = 3841;

透過二級索引列與常數的比較,mysql會在uk_key2的B+樹索引中定位到二級索引紀錄,再根據id值去聚簇索引查詢完整使用者紀錄。

select * from single_table where key2 is NULL;

這個無法使用const存取方法(後續會提到使用什麼方法),因為唯一二級索引並不限制NULL值的數量,所以上述敘述可能存取到多筆紀錄。

ref
透過普通二級索引與常數的相等比較來搜尋一筆紀錄,這個存取方法就是ref,這樣方法的速度慢了const一些。
看個例子:

select * from single_table where key1 = 'abc';

透過普通二級索引與常數的比較,mysql會在idx_key1的B+樹索引中定位到key1='abc'的所有二級索引紀錄(可能很多筆,並不像const是唯一,所以會比較慢),再根據id值去聚簇索引查詢完整使用者紀錄。

以下這樣,只要左邊連續的列都是與常數比較就算是ref

select * from single_table where key_part1 = 'abc';
select * from single_table where key_part1 = 'abc' and key_part2 = 'def';
select * from single_table where key_part1 = 'abc' and key_part2 = 'def' and key_part3 = 'ghi';

但如果有不是相等比較的條件就不算ref

select * from single_table where key_part1 = 'abc' and key_part2 > 'def';

ref_or_null
有時不僅想找出某個二級索引紀錄等於常數的值,也需要NULL值,這個存取方法就是ref_or_null。
看個例子:

select * from single_table where key1 = 'abc' or key1 is NULL;

range
使用索引執行查詢時,對應的掃描區間為許多個單點掃描或範圍掃描區間,這個存取方法就是range。
看個例子:

select * from single_table where key2 in (1,123) or (key2 >= 100 and key2 <= 200);

index

select key_part1, key_part2, key_part3 from single_table where key_part2 = 'abc';

由於key_part2不是聯合索引中最左邊的列,因此無法形成合適的掃描區間(如果不清楚請複習此篇),所以也無法使用前面提到的那些查詢方法。
但這個語法的查詢列表資料(key_part1, key_part2, key_part3)都包含在索引idx_key_part內,搜索條件也一樣。所以我們可以直接利用歷遍idx_key_part二級索引資料就能得到所需的資料,由於二級索引紀錄比聚簇索引紀錄少多了,快上許多,這就是index。

另外order by主鍵也是一種index方法

select * from single_table order by id;

all
全表掃描


上一篇
InnoDB的表格空間-Part3(系統表格空間)
下一篇
索引合併(index merge)
系列文
那些Mysql我不知道的事30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言